#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)//初始化列表构造
{
    ui->setupUi(this);//设置qtdesigner里面的ui关联到widget类的私有变量ui中

    //让子控件随着父窗体大小变化
    // 窗口变化的时候，布局和子控件随之调整
    this->setLayout(ui->verticalLayout);

    // 时间过滤器最后一步就是注册过滤器,只有注册了才会被触发
    // 将父组件的定义好的，注册到textEdit中去,这样就能响应
    ui->textEdit->installEventFilter(this);
//    ui->btnOpen->installEventFilter(this);


    //组件拖拽的时候，下方的行数和不会同时调整吸附在父的边框上
    ui->widgetBottom->setLayout(ui->horizontalLayout);

    // 第二种实现信号与槽的方式
    // 在构造函数中进行信号与槽的绑定
    //发送者 ， 发送了什么信号，接受者，槽（方法名）
    // 不过，如果你的命名遵循规范，也会自动变成他的槽位 on_xx名字_事件
//    QObject::connect(ui->btnSave,SIGNAL(clicked()),
//                     this,SLOT(on_btnSave_clicked()));
//    QObject::connect(ui->btnClose,SIGNAL(clicked()),
//                     this,SLOT(on_btnClose_clicked()));

//    // 第三种，使用lambda表达式，默认方式是this
//    QObject::connect(ui->btnClose,&QPushButton::clicked,[=](){
//        std::cout << "lambda方式" << std::endl;
//    });

//    //第四种方式
//    QObject::connect(ui->btnOpen,&QPushButton::clicked,
//                     this,&Widget::on_btnOpen_clickedMySelf);

//    // 自定义的信号与槽，连接他们,
//    connect(this,SIGNAL(mysignal()),this,SLOT(myslot()));
//    // 如何触发？是用emit关键字，发射信号，触发一个信号
//    emit mysignal();

//    connect(this,SIGNAL(mysignalParam(int)),this,SLOT(myslotParams(int)));

//    emit mysignalParam(1);


    // 初始化一段下拉选择框
//    QStringList items;
//    items.append("GBK");
//    items.append("UTF-8");
    ui->codingComboBox->addItems({"UTF-8","GBK"});

    connect(ui->codingComboBox,SIGNAL(currentIndexChanged(QString)),
            this,
            SLOT(oncurrentIndexChanged(QString)));

    // 创造出文本编辑器的光标事件
    connect(ui->textEdit,SIGNAL(cursorPositionChanged()),
            this,SLOT(onCursorPositionChanged()));


    //增加快捷键
    QShortcut *shortcutOpen = new QShortcut(QKeySequence(tr("Ctrl+O", "File|Open")),
                              this);
    connect(shortcutOpen,&QShortcut::activated
            ,[=](){
                on_btnOpen_clicked();
            });

    QShortcut *shortcutSave = new QShortcut(QKeySequence(tr("Ctrl+S", "File|Save")),
                              this);

    connect(shortcutSave,&QShortcut::activated
            ,[=](){
                    on_btnSave_clicked();
            });

    connect(ui->textEdit,SIGNAL(cursorPositionChanged()),
            this,SLOT(onCursorPositionChanged()));


    // 鼠标滚轮放大字体
    QShortcut *shortcutZoomIn = new QShortcut(QKeySequence(tr("Ctrl+=", "ZoomIn")),
                              this);
    connect(shortcutZoomIn,&QShortcut::activated
            ,[=](){
        qDebug() << "123";
                //获得字体信息
            QFont font = ui->textEdit->font();
                //改变大小
            int size = font.pointSize();
            if(size == -1) return;

            int newFontSize = size +1;
            font.setPointSize(newFontSize);
            ui->textEdit->setFont(font);
            });
    QShortcut *shortcutZoomOut = new QShortcut(QKeySequence(tr("Ctrl+-", "ZoomOut")),
                              this);
    connect(shortcutZoomOut,&QShortcut::activated
            ,[=](){
        qDebug() << "66";
                    //获得字体信息
                QFont font = ui->textEdit->font();
                    //改变大小
                int size = font.pointSize();
                if(size == -1) return;

                int newFontSize = size -1;
                font.setPointSize(newFontSize);
                ui->textEdit->setFont(font);
            });


    // 写一个鼠标滚轮的加ctrl的组合键

//    QShortcut *shortcutWheel = new QShortcut(QKeySequence(tr("Ctrl", "Z")),
//                              this);
//    shortcutWheel->
//    connect(shortcutWheel,&QShortcut::activated,this,
//            Widget::wheelEvent(QWheelEvent *event))
}

Widget::~Widget()
{
    delete ui;
}

void Widget::enterEvent(QEvent *event)
{
 qDebug() << "鼠标进入";
}

void Widget::closeEvent(QCloseEvent *event)
{
qDebug() << "窗口关闭";
int ret = QMessageBox::warning(this, tr("notebook"),
                                tr("你真的要离开吗?"),
                                QMessageBox::Ok| QMessageBox::No);
//检测点击了什么按钮
switch (ret) {
    case QMessageBox::Ok:
    //接受
        event->accept();
    break;
    case QMessageBox::No:
    //不接受
     event->ignore();
    qDebug() << "没关";
    break;
default:break;
}
}

/**
 * @brief Widget::eventFilter
 * @param obj
 * @param ev
 * @return
 *
 * 事件过滤器是事件系统中很重要的一个步骤，事件的发生包括
 *
 * 发起事件->事件过滤->事件分发->事件处理
 * 我们之前都是在事件处理这一步骤，现在我们在事件过滤这个更高层进行处理事件
 */
bool Widget::eventFilter(QObject *obj, QEvent *ev)
{
    /*
    第一个事件是产生的时间的对象
    第二个是发生了什么事件，由于QEvent是所有事件的基类，所以这个Event可以是任何时间
    如果你想处理什么事件，可以将它强转成对应的时间来进行处理
    在这个例子中，我们希望处理ctrl加鼠标滚轮的事件
        */

    if(ev->type()==QEvent::Wheel){
        //首先是滚轮事件，由于这个方法无法同时判断一个事件又是滚轮又是ctrl
        //也就是同一时间只能获得一个事件，所以我们需要使用其它的方式来判断，当前是否有别的按钮还在按下
        if(QGuiApplication::keyboardModifiers()==Qt::ControlModifier){
            //获得当前键盘上按下的修改键位
            QWheelEvent *we = static_cast<QWheelEvent*>(ev);
            if(we->delta()>0){
                qDebug()<<" from textEdit up";
            }else{
                qDebug()<<" from textEdit down";
            }
            //此方法的true可以理解成事件的 e.accecpt()
            // 表示我处理完成，不需要接着传递
            return true;
        }
    }
    // 否则就是ignore，表示不是我要的事件，我不处理，接着往下走
    return false;
}

//void Widget::wheelEvent(QWheelEvent *event)
//{ 现在由自定义控件设置

//    //判断是向上滚还是向下滚

//    /*if(event->delta()>0){
//        qDebug() << "鼠标向上滚动" ;
//    }else{
//        qDebug() << "鼠标向下滚动" ; 让
//    }*/

//}


void file_stream_read(){

    QFile file;
    file.setFileName("H:/QtWorkSpace/notebook/test.txt");
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
        qDebug() << "error";
    }
    QTextStream in(&file) ;
    in.setCodec("UTF-8");
    // 一次性全读取
//    QString context = in.read(file.size());
    QString s = "";
    // 按行读取
    while(!in.atEnd()){
        QString s = in.readLine();
        qDebug()<<s;
    }
    file.close();


}

void file_stream_write(){
    QFile file;
    file.setFileName("H:/QtWorkSpace/notebook/test2.txt");
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
        qDebug() << "error";
    }
    QTextStream out(&file) ;
    out.setCodec("utf-8");
    QString s = "中文";//如果想要使用中文，可以先这样写，在输出不会乱码
    out << s;
    // 按行读取
    file.close();
}

void file_about(){

    //打开文件 可以通过手册来查询资料，help
//    QFile file("H:/QtWorkSpace/notebook/test.txt");
//    bool is = file.open(QIODevice::ReadOnly | QIODevice::Text);
//    if(is){
//        //读取
//        char content[100];
//        //缓冲的数组，要读多少
//        file.read(content,100);
//        qDebug() << content;
//    }else{
//        qDebug() << "打开失败";
//    }


//    file.close();

    //写入文件
//    QFile file("H:/QtWorkSpace/notebook/test2.txt");

//    file.open(QIODevice::WriteOnly |  QIODevice::Text);
//    //
//    file.write("22222222222速读法");
//    file.close();
}
// 保存文件 另存为
void open_file_save(QWidget *parent){
    /*
 QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                            "/home/jana/untitled.png",
                            tr("Images (*.png *.xpm *.jpg)"));
*/
    QString fileName = QFileDialog::getSaveFileName(parent, QObject::tr("保存文件"),
                               "H:/QtWorkSpace/notebook/untitled.txt",
                               QObject::tr("Text (*.txt)"));
    qDebug() << fileName;
    //拿到文件的名字后就可以写入
    QFile file(fileName);
    file.open(QIODevice::WriteOnly | QIODevice::Text);
    QTextStream out(&file);
    out.setCodec("utf-8");
    out << QObject::tr("写了写什么");
    file.close();
}

/*
文件选择，选择多个文件，或者选择一个文件夹
*/
void open_file_mult_dialog(QWidget *parent){

    QFileDialog qFileDialog;
    //选择打开的模式，你可以选择打开一个存在的文件，或者打开一个文件夹来选择多个文件
    qFileDialog.setFileMode(QFileDialog::ExistingFiles);

    //打开的时候限定文件
    qFileDialog.setNameFilter(QObject::tr("Text files123 (*.txt)"));

    if(qFileDialog.exec()){
        //获取选择的文件
        QStringList list = qFileDialog.selectedFiles();
        //展示所有选择的文件
//        QStringListIterator javaStyleIterator(list);
//             while (javaStyleIterator.hasNext())
//                  qDebug() << javaStyleIterator.next().toLocal8Bit().constData();
        for(QString fileName:list){
            qDebug() << fileName;
        }
    }
}

void open_file_dialog(QWidget *parent){
    //弹出文件选择框
    /*
getOpenFileName(QWidget *parent = nullptr,
const QString &caption = QString(),
 const QString &dir = QString(),
const QString &filter = QString(),
QString *selectedFilter = nullptr,
QFileDialog::Options options = Options())
*/
    QString fileName = QFileDialog::getOpenFileName(parent,
                                 QObject::tr("一个打开的对话框"),//标题名
                                 //默认打开路径
                                 "H:/QtWorkSpace/notebook/",
                                 //过滤器，看起来签名的名字可以随便和正则都可以自定义
//                                 QObject::tr("Images (*.png *.xpm *.jpg)"
//                                             ";;Text files123 (*.txt);;XML files (*.xml)")
                                                    QObject::tr("Text files123 (*.txt);;XML files (*.xml)")
                                                    );
    qDebug() << fileName;
    //拿到路径后，我们就可以指定读取对应文本的内容了。
    //不过这里可能要判断你选择是什么后缀的
    QFile file(fileName);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
           qDebug() << QObject::tr("打开失败");

    }else{
        //是否要判断后缀

        QTextStream in(&file);
        //使用下拉框的内容来编码

        in.setCodec("utf-8");
        while(!in.atEnd()){
            QString s = in.readLine();
            qDebug() << s;
        }
    }
    file.close();
}

// 第一种实现
// 通过ui界面，右键转到槽，选择对应的信号事件qt会自动生成这行代码
void Widget::on_btnOpen_clicked()
{
//     std::cout << "ui界面方式" << std::endl;
//    file_stream_write();
//    open_file_dialog(this);
//    open_file_mult_dialog(this);
//    open_file_save(this);


    QString fileName = QFileDialog::getOpenFileName(this,
                                 QObject::tr("一个打开的对话框"),//标题名
                                 //默认打开路径
                                 "H:/QtWorkSpace/notebook/",
                                 //过滤器，看起来签名的名字可以随便和正则都可以自定义
                                 QObject::tr("Text files123 (*.txt);;XML files (*.xml)")
                                 );
    qDebug() << fileName;
    this->setWindowTitle(fileName);
    ui->textEdit->clear();//每次选择清空文本
    //拿到路径后，我们就可以指定读取对应文本的内容了。
    //不过这里可能要判断你选择是什么后缀的
    file.setFileName(fileName);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
           qDebug() << QObject::tr("打开失败");

    }else{
        //是否要判断后缀

        QTextStream in(&file);
        QString s =ui->codingComboBox->currentText();
        //将qString，转换为 c++的字符串，转化为char数组
        const char* char_st = s.toStdString().c_str();
        in.setCodec(char_st);
        while(!in.atEnd()){
            QString s = in.readLine();
            // 文件写入到文本编辑器
//            qDebug() << s;
            //这是直接替换文本，我们需要追加
//            ui->textEdit->setText(s);
            ui->textEdit->append(s);
        }
    }
    file.close();
}

void Widget::on_btnSave_clicked()
{
    qDebug()<<QObject::tr("点击保存");
    QString fileName = QFileDialog::getSaveFileName(this, QObject::tr("保存文件"),
                               "H:/QtWorkSpace/notebook/untitled.txt",
                               QObject::tr("Text (*.txt)"));
    qDebug() << fileName;
    //拿到文件的名字后就可以写入
    QFile file(fileName);
    file.open(QIODevice::WriteOnly | QIODevice::Text);
    QTextStream out(&file);
    out.setCodec("utf-8");

    //拿到文本
    QString s = ui->textEdit->toPlainText();

    out << s;
    file.close();
}

void Widget::on_btnClose_clicked()
{
    qDebug()<<QObject::tr("点击关闭");
    // 关闭前，判断文件是否修改
    //开始前持有了一个文件，判断这个文件是否有东西
    if(file.isOpen()){
       //如果已经被打开，提示写什么
        file.close();
        ui->textEdit->clear();
    }
    //或者文本编辑的内容已经修改，判断是否关闭时保存
    //    ui->textEdit->
}

void Widget::oncurrentIndexChanged(QString text)
{
    qDebug() << text;
    //拿到选中的格式
    //首先将编辑文本内的内容清空，然后重新将内容编码输入
    if(orgText.isNull()){
        orgText= ui->textEdit->toPlainText();
    }
    QString t = orgText;
    //重新编译成对应编码，然后写入
//    const char* codingName = text.toStdString().c_str();
    ui->labelEndcoding->setText(text);
    QTextCodec *codec = QTextCodec::codecForName(text.toLocal8Bit());

    QString ne = codec->toUnicode(t.toLocal8Bit());

    ui->textEdit->clear();
    ui->textEdit->append(ne);


}

void Widget::onCursorPositionChanged()
{
    //改变展示，多少行，多少列
    QTextCursor cursor = ui->textEdit->textCursor();
    //获取文本的光标
    //多少行
    QString col = QString::number(cursor.columnNumber()+1);
    QString row = QString::number(cursor.blockNumber()+1);
    const QString str = ""+row+ "行,"+col+"列 |";
    ui->labelPosition->setText(str);
//    qDebug() << col << "," << row;
    // 设置当前行高亮
    QList<QTextEdit::ExtraSelection> extraSelections;
    QTextEdit::ExtraSelection ext;

    // 直到当前行
    ext.cursor = cursor;
    // 颜色
    QBrush brush(Qt::yellow);
//    QColor c;
//    c.setRgb(255,255,255);
//    brush.setColor();
    ext.format.setBackground(brush);
    // 整行设置
    ext.format.setProperty(QTextFormat::FullWidthSelection,true);
    extraSelections.append(ext);
    //设置
    ui->textEdit->setExtraSelections(extraSelections);
}








void Widget::myslot()
{
    std::cout << "自定义myslot方式" << std::endl;
}

void Widget::myslotParams(int value)
{
    qDebug() << "自定义myslotParams方式" << value;
//    qInfo()

}


